-
Notifications
You must be signed in to change notification settings - Fork 4.6k
balancer/randomsubsetting: Implementation of the random_subsetting LB policy #8650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: marek-szews <[email protected]>
|
@marek-szews : Could you please get the tests to pass. Thanks. |
| } | ||
|
|
||
| // if someonw needs subsetSize == 1, he should use pick_first instead | ||
| if lbCfg.SubsetSize < 2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gRFC only says the following:
// The value is required and must be greater than 0.
Is the condition that the size be at least 2 specified somewhere else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the discussion at line 86
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 86 of what?
The only thing we should be checking is whether the subset size is greater than 0 and if not, returning an error from this method.
|
This PR is labeled as requiring an update from the reporter, and no update has been received after 6 days. If no update is provided in the next 7 days, this issue will be automatically closed. |
|
Hi @marek-szews - I think we're waiting on you to make some updates so we can continue the review. We can discuss Friday but I wanted to ping this in part to prevent the stale bot from closing it. |
marek-szews
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rework done, tests passed
Tests are still failing. Please read this document for guidelines: https://github.com/grpc/grpc-go/blob/master/CONTRIBUTING.md TL;dr |
| } | ||
|
|
||
| if b.cfg == nil || b.cfg.ChildPolicy.Name != lbCfg.ChildPolicy.Name { | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this newline.
| type lbConfig struct { | ||
| serviceconfig.LoadBalancingConfig `json:"-"` | ||
|
|
||
| SubsetSize uint64 `json:"subsetSize,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be uint32 as per the gRFC.
| func (b *subsettingBalancer) prepareChildResolverState(s balancer.ClientConnState) resolver.State { | ||
| subsetSize := b.cfg.SubsetSize | ||
| endPoints := s.ResolverState.Endpoints | ||
| backendCount := len(endPoints) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Please get rid of the backendCount local variable. The cide is more readable when used as len(endpoints).
| // as described in A68: https://github.com/grpc/proposal/blob/master/A68-random-subsetting.md | ||
| func (b *subsettingBalancer) prepareChildResolverState(s balancer.ClientConnState) resolver.State { | ||
| subsetSize := b.cfg.SubsetSize | ||
| endPoints := s.ResolverState.Endpoints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: s/endPoints/endpoints/
endpoint is a single word.
|
|
||
| // sort endpoint by hash | ||
| slices.SortFunc(endpointSet, func(a, b endpointWithHash) int { | ||
| return cmp.Compare(a.hash, b.hash) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not use the cmp package in non-test code. The cmp package is only meant for test code. Please use the < operator here as the hash field is a uint64
| // The backend receives a second request from the same client. This could happen if the client have 1 backend in READY | ||
| // state while the other are CONNECTING. In this case round_robbin will pick the same address twice. | ||
| // We are going to retry after short timeout. | ||
| time.Sleep(10 * time.Microsecond) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid sleeping in tests.
| return clients, cancel | ||
| } | ||
|
|
||
| func checkRoundRobinRPCs(ctx context.Context, t *testing.T, clients []testgrpc.TestServiceClient, subsetSize int, maxDiff int) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have something like this already:
| func CheckRoundRobinRPCs(ctx context.Context, client testgrpc.TestServiceClient, addrs []resolver.Address) error { |
Would you be able to use that instead? Thanks
| cancel := func() { | ||
| for _, cc := range ccs { | ||
| cc.Close() | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use t.Cleanup here as well and avoid having to return a cancel function that the test needs to invoke.
| maxDiff int | ||
| }{ | ||
| { | ||
| name: "backends could be evenly distributed between small number of clients", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see here for guidelines on how best to name subtests: https://google.github.io/styleguide/go/decisions#subtest-names
TL;dr
Think of subtest names more like a function identifier than a prose description.
The test runner replaces spaces with underscores, and escapes non-printing characters. To ensure accurate correlation between test logs and source code, it is recommended to avoid using these characters in subtest names.
| func (bb) Build(cc balancer.ClientConn, bOpts balancer.BuildOptions) balancer.Balancer { | ||
| b := &subsettingBalancer{ | ||
| Balancer: gracefulswitch.NewBalancer(cc, bOpts), | ||
| hashf: xxhash.NewWithSeed(uint64(time.Now().UnixNano())), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably want to use a random number here as specified in the gRFC. Also, it would be useful to be able to override the random value in tests for predictability. Here is an example of how to do what I'm suggesting:
grpc-go/internal/wrr/random.go
Line 49 in c0de489
| var randInt64n = rand.Int64N |
Implements [gRFC A68]https://github.com/grpc/proposal/blob/master/A68-random-subsetting.md.
Note that this PR only implements the LB policy and does not implement the xDS integration specified here: https://github.com/grpc/proposal/blob/master/A68-random-subsetting.md#xds-integration
RELEASE NOTES:
random_subsettingLB policy